﻿#include "QTandOpenCV.h"
#include "opencv.hpp"
#include <qgraphicsscene.h>
#include <qcolordialog.h>
#include <qpalette.h>
#include <qtimer.h>
#include <qfiledialog.h>
#include <qlineedit.h>
#include <qspinbox.h>
#include <qmessagebox.h>
#include <qlabel.h>
#include "cvPro.h"


namespace OpenCVFunc {
    QStringList funcList = {
        QStringLiteral("基本绘图"),
        QStringLiteral("随机数和文本绘制"),
        QStringLiteral("滤波器"),
        QStringLiteral("腐蚀/膨胀"),
    };
    int funcId = 0;
}

QTandOpenCV::QTandOpenCV(QWidget* parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    comboboxAddBtn();
    //btnCSSset();
}

QTandOpenCV::~QTandOpenCV()
{
}

void QTandOpenCV::on_background_clicked() {
    QColor color = QColorDialog::getColor(Qt::white, this, "背景颜色");
    if (color.isValid()) {
        this->setStyleSheet(QString("background-color:%1;").arg(color.name()));
    }
}

void QTandOpenCV::comboboxAddBtn() {
    ui.ProSelect->addItem(QString("不选择"));
    for (const auto& name : OpenCVFunc::funcList) {
        ui.ProSelect->addItem(name);
    }
}

void QTandOpenCV::on_ProSelect_activated(int selectIndex) {
    OpenCVFunc::funcId = selectIndex;
    removeFilterWidget();
}

void QTandOpenCV::on_startBtn_clicked() {
    int width = ui.showImg01->size().width() - 10;
    int height = ui.showImg01->size().height() - 10;
    switch (OpenCVFunc::funcId)
    {
    case 1:
    {
        textImgClear();
        cv::Mat img01, img02;
        img01 = cv::Mat::zeros(height, width, CV_8UC3);
        img02 = cv::Mat::zeros(height, width, CV_8UC3);
        plotLearn(img01, img02, width, height);
        openCVImgShow(img01, ui.showImg01);
        openCVImgShow(img02, ui.showImg02);
        break;
    }
    case 2:
    {
        textImgClear();
        cv::Mat img01, img02, img03;
        img01 = cv::Mat::zeros(height, width, CV_8UC3);
        img02 = cv::Mat::zeros(height, width, CV_8UC3);
        img03 = cv::Mat::zeros(height, width, CV_8UC3);
        randomLearn(img01, img02, img03, width, height);
        openCVImgShow(img01, ui.showImg01);
        openCVImgShow(img02, ui.showImg02);
        openCVImgShow(img03, ui.showImg03);
        break;
    }
    case 3:
    {
        textImgClear();
        filterWidget();
        break;
    }
    case 4: 
    {
        textImgClear();
        ui.Introduction01->setPlainText(
            QString(
                "腐蚀：\n"
                "腐蚀操作通过将图像中的前景像素（通常为白色）缩小来去除噪声和分离连接的对象。"));
        EDWidget();
        break;
    }
    default:
    {
        textImgClear();
        ui.Introduction01->setPlainText(QString("未选择功能"));
        break;
    }
    }
}

void QTandOpenCV::textImgClear() {
    ui.Introduction01->setPlainText(QString("说明"));
    if (ui.showImg01->scene()) ui.showImg01->scene()->clear();
    if (ui.showImg02->scene()) ui.showImg02->scene()->clear();
    if (ui.showImg03->scene()) ui.showImg03->scene()->clear();
}

void QTandOpenCV::openCVImgShow(cv::Mat img, QGraphicsView* graphicview) {
    cv::cvtColor(img, img, cv::COLOR_BGR2RGB); // 转换为 RGB
    QImage qImage01(img.data, img.cols, img.rows, img.step, QImage::Format_RGB888);
    QGraphicsScene* scene01 = new QGraphicsScene(this);
    scene01->addPixmap(QPixmap::fromImage(qImage01));
    graphicview->setScene(scene01);
    graphicview->show();
}

void QTandOpenCV::btnCSSset() {
    QString metalStyle =
        "QPushButton {"
        "    border: 2px solid #A9A9A9;"  // 边框颜色稍深一些
        "    border-radius: 12px;"       // 保留圆角
        // 移除了 padding 设置以避免影响按钮尺寸
        "    background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "        stop:0 #C0C0C0, stop:0.5 #A0A0A0, stop:1 #E0E0E0);"  // 更深的银灰色渐变
        "    color: #333;"
        "    font-weight: bold;"
        "    box-shadow: 0px 4px 8px rgba(120,120,120,0.5);"  // 增强阴影效果
        "}"
        "QPushButton:hover {"
        "    background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "        stop:0 #D0D0D0, stop:0.5 #B0B0B0, stop:1 #F0F0F0);"  // 悬停时更亮
        "    border: 2px solid #808080;"  // 边框颜色加深
        "}"
        "QPushButton:pressed {"
        "    background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "        stop:0 #A0A0A0, stop:0.5 #808080, stop:1 #C0C0C0);"  // 按下时更深
        "    border-style: inset;"  // 凹陷效果
        "}";
    QString metalComboStyle =
        "QComboBox {"
        "    border: 2px solid #A9A9A9;"
        "    border-radius: 12px;"       // 保留圆角
        // 未直接设置 padding，保持原有尺寸
        "    background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "        stop:0 #C0C0C0, stop:0.5 #A0A0A0, stop:1 #E0E0E0);"  // 更深的银灰色渐变
        "    color: #333;"
        "    font-weight: bold;"
        "}"
        "QComboBox::drop-down {"
        "    border: none;"
        "    border-radius: 6px;"
        "    width: 28px;"
        "    background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
        "        stop:0 #E0E0E0, stop:1 #A0A0A0);"
        "}"
        "QComboBox::down-arrow {"
        "    width: 18px; height: 18px;"
        "    image: none;"
        "    border: none;"
        "    background: none;"
        "}"
        "QComboBox::down-arrow {"
        "    position: center;"
        "}"
        "QComboBox::down-arrow:enabled {"
        "    border: none;"
        "    background: none;"
        "    width: 0; height: 0;"
        "    border-left: 9px solid transparent;"
        "    border-right: 9px solid transparent;"
        "    border-top: 9px solid #333;"
        "    margin: 5px;"
        "}"
        "QComboBox QAbstractItemView {"
        "    border: 1px solid #A9A9A9;"
        "    background: #E0E0E0;"  // 使用相同的银灰色背景
        "    selection-background-color: #B0B0B0;"
        "    color: #333;"
        "}";
    ui.startBtn->setStyleSheet(metalStyle);
	ui.background->setStyleSheet(metalStyle);
	ui.ProSelect->setStyleSheet(metalComboStyle);
}

void QTandOpenCV::filterWidget() {
    QPushButton* selectFileBtn = new QPushButton("请选择图片");
	selectFileBtn->setObjectName("selectFileBtn");
    QLineEdit* fileEdit = new QLineEdit(this);
	fileEdit->setObjectName("fileEdit");
    ui.vLayout01->addWidget(selectFileBtn);
    ui.vLayout01->addWidget(fileEdit);

    connect(selectFileBtn, &QPushButton::clicked, this, [=]() {
        QString fileName = QFileDialog::getOpenFileName(this, "选择图片", "", "Images (*.png *.xpm *.jpg *.bmp);;All Files (*)");
		
        if (!fileName.isEmpty()) {
            fileEdit->setText(fileName);
            QComboBox* filterComboBox = new QComboBox(this);
            filterComboBox->setObjectName("filterComboBox");
            filterComboBox->addItem("均值滤波");
            filterComboBox->addItem("高斯滤波");
            filterComboBox->addItem("中值滤波");
            filterComboBox->addItem("双边滤波");
            ui.vLayout01->addWidget(filterComboBox);
            QSpinBox* kernelSizeBox = new QSpinBox(this);
			kernelSizeBox->setObjectName("kernelSizeBox");
            ui.vLayout01->addWidget(kernelSizeBox);
            QPushButton* startFilterBtn = new QPushButton("开始滤波");
			startFilterBtn->setObjectName("startFilterBtn");
            ui.vLayout01->addWidget(startFilterBtn);
            kernelSizeBox->setValue(3);
            kernelSizeBox->setMinimum(1);
            kernelSizeBox->setMaximum(31);
            kernelSizeBox->setSingleStep(2);
            kernelSizeBox->setToolTip("请输入奇数");
            ui.Introduction01->setPlainText(
                QString(
                    "均值滤波：\n"
                    "均值滤波是一种简单且常用的图像平滑技术，"
                    "通过将每个像素的值替换为其邻域内像素值的平均值来减少图像中的噪声和细节。"));
            connect(filterComboBox, QOverload<int>::of(&QComboBox::activated), this, [=](int index) {
                switch (index)
                {
                case 0:
                    kernelSizeBox->setValue(3);
                    kernelSizeBox->setMinimum(1);
                    kernelSizeBox->setMaximum(31);
                    kernelSizeBox->setSingleStep(2);
                    kernelSizeBox->setToolTip("请输入奇数");
                    ui.Introduction01->setPlainText(
                        QString(
                            "均值滤波：\n"
                            "均值滤波是一种简单且常用的图像平滑技术，"
                            "通过将每个像素的值替换为其邻域内像素值的平均值来减少图像中的噪声和细节。"));
                    break;
                case 1:
                    kernelSizeBox->setValue(3);
                    kernelSizeBox->setMinimum(1);
                    kernelSizeBox->setMaximum(31);
                    kernelSizeBox->setSingleStep(2);
                    kernelSizeBox->setToolTip("请输入奇数");
                    ui.Introduction01->setPlainText(
                        QString(
                            "高斯滤波：\n"
                            "高斯滤波是一种基于高斯函数的图像平滑技术，"
                            "通过对图像进行加权平均来减少噪声，同时保留边缘信息。"));
                    break;
                case 2:
                    kernelSizeBox->setValue(3);
                    kernelSizeBox->setMinimum(1);
                    kernelSizeBox->setMaximum(31);
                    kernelSizeBox->setSingleStep(2);
                    kernelSizeBox->setToolTip("请输入奇数");
                    ui.Introduction01->setPlainText(
                        QString(
                            "中值滤波：\n"
                            "中值滤波是一种非线性图像平滑技术，"
                            "通过将每个像素的值替换为其邻域内像素值的中位数来有效去除椒盐噪声。"));
                    break;
                case 3:
                    kernelSizeBox->setValue(9);
                    kernelSizeBox->setMinimum(9);
                    kernelSizeBox->setMaximum(255);
                    kernelSizeBox->setSingleStep(2);
                    kernelSizeBox->setToolTip("请输入正数");
                    ui.Introduction01->setPlainText(
                        QString(
                            "双边滤波：\n"
                            "双边滤波是一种同时考虑空间距离和像素值差异的图像平滑技术，"
                            "双边滤波可以很好地减少不必要的噪声，同时保持边缘相当锐利。然而，与大多数滤波器相比，它非常慢。"));
                    break;
                default:
                    break;
                }});
            connect(startFilterBtn, &QPushButton::clicked, this, [=]() {
                QString filePath = fileEdit->text();
                if (filePath.isEmpty()) {
                    ui.Introduction01->setPlainText(QString("请先选择图片"));
                    return;
                }
                cv::Mat img = cv::imread(filePath.toStdString());
                if (img.empty()) {
                    ui.Introduction01->setPlainText(QString("无法打开图片，请检查文件路径"));
                    return;
                }
                if (ui.showImg01->scene()) ui.showImg01->scene()->clear();
                if (ui.showImg02->scene()) ui.showImg02->scene()->clear();
                if (ui.showImg03->scene()) ui.showImg03->scene()->clear();
                cv::Mat imgResized;
                cv::resize(img, imgResized, cv::Size(ui.showImg01->size().width() - 10, ui.showImg01->size().height() - 10));
                openCVImgShow(imgResized, ui.showImg01);
                cv::Mat imgFiltered;
                int ksize = kernelSizeBox->value();
                if (filterComboBox->currentIndex() > 0 && filterComboBox->currentIndex() < 3 && ksize % 2 == 0) {
                    kernelSizeBox->setValue(ksize - 1);
                    QMessageBox::warning(this, "警告", "该滤波器的滤波核大小必须为正奇数，已自动调整为最近的正奇数");
                }
                else {
                    filterLearn(imgResized, imgFiltered, filterComboBox->currentIndex(), ksize);
                    openCVImgShow(imgFiltered, ui.showImg02);
                }
                });
        }});
}

void QTandOpenCV::removeFilterWidget() {
	QComboBox* filterComboBox = ui.groupBox->findChild<QComboBox*>("filterComboBox");
	QSpinBox* kernelSizeBox = ui.groupBox->findChild<QSpinBox*>("kernelSizeBox");
	QPushButton* startFilterBtn = ui.groupBox->findChild<QPushButton*>("startFilterBtn");
	QPushButton* selectFileBtn = ui.groupBox->findChild<QPushButton*>("selectFileBtn");
	QLineEdit* fileEdit = ui.groupBox->findChild<QLineEdit*>();
	if (filterComboBox) 
    {
        ui.vLayout01->removeWidget(filterComboBox);
		delete filterComboBox;
    }
    if(kernelSizeBox)
    {
        ui.vLayout01->removeWidget(kernelSizeBox);
        delete kernelSizeBox;
	}
    if(startFilterBtn)
    {
        ui.vLayout01->removeWidget(startFilterBtn);
        delete startFilterBtn;
	}
    if(selectFileBtn)
    {
        ui.vLayout01->removeWidget(selectFileBtn);
        delete selectFileBtn;
    }
    if(fileEdit)
    {
        ui.vLayout01->removeWidget(fileEdit);
        delete fileEdit;
	}
	textImgClear();
}

void QTandOpenCV::EDWidget() {
    QComboBox* EDComboBox = new QComboBox(this);
    EDComboBox->setObjectName("EDComboBox");
    EDComboBox->addItem("腐蚀");
    EDComboBox->addItem("膨胀");
    bool chooseErosion = true;
	ui.vLayout01->addWidget(EDComboBox);
    QPushButton* selectFileBtn = new QPushButton("请选择图片");
    selectFileBtn->setObjectName("selectFileBtn");
    QLineEdit* fileEdit = new QLineEdit(this);
    fileEdit->setObjectName("fileEdit");
    ui.vLayout01->addWidget(selectFileBtn);
    ui.vLayout01->addWidget(fileEdit);
    connect(selectFileBtn, &QPushButton::clicked, this, [=]() {
        QString fileName = QFileDialog::getOpenFileName(this, "选择图片", "", "Images (*.png *.xpm *.jpg *.bmp);;All Files (*)");

        if (!fileName.isEmpty()) {
            fileEdit->setText(fileName);
        }
     });

	QLabel* shapeLabel = new QLabel("元素形状", this);
    QComboBox* shapeComboBox = new QComboBox(this);
    shapeComboBox->setObjectName("shapeComboBox");
    shapeComboBox->addItem("矩形");
    shapeComboBox->addItem("十字形");
    shapeComboBox->addItem("椭圆形");
	QHBoxLayout* shapeLayout = new QHBoxLayout(this);
	shapeLayout->addWidget(shapeLabel, 1);
	shapeLayout->addWidget(shapeComboBox, 2);
	ui.vLayout01->addLayout(shapeLayout);
        
	QPushButton* startEDBtn = new QPushButton("开始操作");
	startEDBtn->setObjectName("startEDBtn");
	ui.vLayout01->addWidget(startEDBtn);

    QLabel* ksizeLabel = new QLabel("ksize", this);
	QSpinBox* ksizeSpinBox = new QSpinBox(this);
    QHBoxLayout* kenerLayout = new QHBoxLayout(this);
    QSlider* ksizeSlider = new QSlider(Qt::Horizontal);
    ksizeSpinBox->setMinimum(1);
    ksizeSpinBox->setMaximum(99);
    ksizeSpinBox->setSingleStep(2);
    kenerLayout->addWidget(ksizeLabel, 1);
    kenerLayout->addWidget(ksizeSpinBox, 2);
    ui.vLayout01->addLayout(kenerLayout);
    ksizeSlider->setMinimum(1);
    ksizeSlider->setMaximum(99);
    ui.vLayout01->addWidget(ksizeSlider);

    QLabel* anchorXLabel = new QLabel("anchorX", this);
    QSpinBox* anchorXSpinBox = new QSpinBox(this);
    QHBoxLayout* anchorXLayout = new QHBoxLayout(this);
    QSlider* anchorXSlider = new QSlider(Qt::Horizontal);
    anchorXSpinBox->setMinimum(-1);
    anchorXSpinBox->setMaximum(99);
    anchorXLayout->addWidget(anchorXLabel, 1);
    anchorXLayout->addWidget(anchorXSpinBox, 2);
    ui.vLayout01->addLayout(anchorXLayout);
    anchorXSlider->setMinimum(-1);
    anchorXSlider->setMaximum(99);
    ui.vLayout01->addWidget(anchorXSlider);

    QLabel* anchorYLabel = new QLabel("anchorY", this);
    QSpinBox* anchorYSpinBox = new QSpinBox(this);
    QHBoxLayout* anchorYLayout = new QHBoxLayout(this);
    QSlider* anchorYSlider = new QSlider(Qt::Horizontal);
    anchorYSpinBox->setMinimum(-1);
    anchorYSpinBox->setMaximum(98);
    anchorYLayout->addWidget(anchorYLabel, 1);
    anchorYLayout->addWidget(anchorYSpinBox, 2);
    ui.vLayout01->addLayout(anchorYLayout);
    anchorYSlider->setMinimum(-1);
    anchorYSlider->setMaximum(98);
    ui.vLayout01->addWidget(anchorYSlider);

    connect(EDComboBox, QOverload<int>::of(&QComboBox::activated), this, [&](int index) {
        switch (index)
        {
        case 0:
            chooseErosion = true;
            ui.Introduction01->setPlainText(
                QString(
                    "腐蚀：\n"
                    "腐蚀操作通过将图像中的前景像素（通常为白色）缩小来去除噪声和分离连接的对象。"));
            break;
        case 1:
            chooseErosion = false;
            ui.Introduction01->setPlainText(
                QString(
                    "膨胀：\n"
                    "膨胀操作通过将图像中的前景像素（通常为白色）扩大来填补小孔洞和连接断开的对象。"));
            break;
        default:
            break;
        }
		});

    connect(ksizeSlider, &QSlider::valueChanged, ksizeSpinBox, &QSpinBox::setValue);
    connect(ksizeSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), ksizeSlider, &QSlider::setValue);

    connect(anchorXSlider, &QSlider::valueChanged, anchorXSpinBox, &QSpinBox::setValue);
    connect(anchorXSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), anchorXSlider, &QSlider::setValue);

    connect(anchorYSlider, &QSlider::valueChanged, anchorYSpinBox, &QSpinBox::setValue);
    connect(anchorYSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), anchorYSlider, &QSlider::setValue);

    connect(startEDBtn, &QPushButton::clicked, this, [=]() {
		if (ksizeSpinBox->value() % 2 == 0) ksizeSpinBox->setValue(ksizeSpinBox->value() - 1);
        cv::Size ksize(ksizeSpinBox->value(), ksizeSpinBox->value());
        cv::Point anchor(anchorXSpinBox->value(), anchorYSpinBox->value());
        int shapeType = shapeComboBox->currentIndex();
        if (shapeType == 0) { shapeType = cv::MORPH_RECT; }
        else if (shapeType == 1) { shapeType = cv::MORPH_CROSS; }
        else if (shapeType == 2) { shapeType = cv::MORPH_ELLIPSE; }
        QString filePath = fileEdit->text();
        if (filePath.isEmpty()) {
            ui.Introduction01->setPlainText(QString("请先选择图片"));
            return;
        }
        cv::Mat img = cv::imread(filePath.toStdString(), cv::IMREAD_COLOR);
        if (img.empty()) {
            ui.Introduction01->setPlainText(QString("无法打开图片，请检查文件路径"));
            return;
        }
        if (ui.showImg01->scene()) ui.showImg01->scene()->clear();
        if (ui.showImg02->scene()) ui.showImg02->scene()->clear();
        if (ui.showImg03->scene()) ui.showImg03->scene()->clear();
        cv::Mat imgResized;
        cv::resize(img, imgResized, cv::Size(ui.showImg01->size().width() - 10, ui.showImg01->size().height() - 10));
        openCVImgShow(imgResized, ui.showImg01);
        cv::Mat imgED;
        ErosionOrDilation(imgResized, imgED, shapeType, ksize, anchor, chooseErosion);
        openCVImgShow(imgED, ui.showImg02);
        });
}
